package com.xinzhitong.www.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xinzhitong.www.exception.*;
import com.xinzhitong.www.exception.questionanalysis.TypeErrException;
import com.xinzhitong.www.exception.questionbank.QuestionBankEmptyException;
import com.xinzhitong.www.exception.questioncard.NoQuestionCardException;
import com.xinzhitong.www.exception.questionerr.NoErrQuestionException;
import com.xinzhitong.www.exception.questionerr.QuestionAnswerIsNullException;
import com.xinzhitong.www.exception.questionerrid.NoQuestionErrIdException;
import com.xinzhitong.www.exception.questioninformation.NoQuestionInformationException;
import com.xinzhitong.www.exception.questionmessage.NoQuestionMessageException;
import com.xinzhitong.www.exception.questionsign.InvalidSignOfTheQuestionException;
import com.xinzhitong.www.exception.questionsign.MultiSignOfSameQuestionException;
import com.xinzhitong.www.exception.test.EmptyTestOfTheCredentialException;
import com.xinzhitong.www.exception.test.EmptyTestOfTheProfessionException;
import com.xinzhitong.www.mapper.QuestionBankMapper;
import com.xinzhitong.www.pojo.TestInfo;
import com.xinzhitong.www.pojo.User;
import com.xinzhitong.www.service.QuestionBankService;
import com.xinzhitong.www.utils.FileHelper;
import com.xinzhitong.www.utils.MyPageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

/**
 * 题库服务实现类
 *
 * @author 徐鑫 魏骆淳 钟伟良
 */
@Service
@Transactional
public class QuestionBankServiceImpl implements QuestionBankService {

    @Resource
    QuestionBankMapper questionBankMapper;

    /**
     * 题目类型
     */
    private static String[] questionTypes = new String[]{
            "单选",
            "多选",
            "判断",
            "填空",
            "论述"
    };

    @Override
    public MyPageInfo getQuestionBanks(Integer professionId, Integer pageNo, Integer pageSize) throws QuestionBankException {
        Subject subject = SecurityUtils.getSubject();
        String username = ((User) subject.getPrincipal()).getUsername();

        PageHelper.startPage(pageNo, pageSize);
        List<Map<String, Object>> questionBanks = questionBankMapper.selectQuestionBanks(username, professionId);
        //补充url
        for (Map<String, Object> questionBank : questionBanks)
            questionBank.put("picture", FileHelper.fileURL + questionBank.get("picture"));

        if (questionBanks.size() == 0)
            throw new QuestionBankEmptyException();
        PageInfo<Map<String, Object>> pageInfo =
                new PageInfo<>(questionBanks);
        return new MyPageInfo(pageInfo);
    }

    @Override
    public Map<String, Object> getAnswerIsCorrect(
            Integer questionId,
            String questionType,
            List<String> userQuestionAnswer
    ) throws QuestionBankException {
        List<Map<String, Object>> questionAnswer = questionBankMapper.selectAnswerIsCorrect(questionId, questionType);
        if (questionAnswer == null) {
            throw new QuestionAnswerIsNullException();
        } else {
            Subject subject = SecurityUtils.getSubject();
            User user = (User) subject.getPrincipal();
            Map<String, Object> map = new HashMap<>();

            //判断题
            if (questionType.equals("判断")) {
                if (questionAnswer.get(0).get("judgeIsCorrect") == null) {
                    throw new QuestionAnswerIsNullException();
                } else {
                    map.put("correctAnswer", questionAnswer.get(0).get("judgeIsCorrect"));
                    if (Boolean.valueOf(userQuestionAnswer.get(0)) == questionAnswer.get(0).get("judgeIsCorrect")) {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                TRUE,
                                userQuestionAnswer.get(0)
                        );
                        map.put("answerIsCorrect", TRUE);
                    } else {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                FALSE,
                                userQuestionAnswer.get(0)
                        );
                        map.put("answerIsCorrect", FALSE);
                    }
                    return map;
                }

                //单选题
            } else if (questionType.equals("单选")) {
                List<Map<String, Object>> optionCode = questionBankMapper.selectOptionCode(questionId, TRUE);
                if (optionCode.size() == 0) {
                    throw new QuestionAnswerIsNullException();
                } else {
                    if (userQuestionAnswer.get(0).equals(optionCode.get(0).get("optionCode"))) {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                TRUE,
                                userQuestionAnswer.get(0)
                        );
                        map.put("answerIsCorrect", TRUE);
                    } else {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                FALSE,
                                userQuestionAnswer.get(0)
                        );
                        map.put("answerIsCorrect", FALSE);
                    }
                    map.put("correctAnswer", optionCode.get(0).get("optionCode"));
                    return map;
                }

                //多选题
            } else {
                List<Map<String, Object>> optionCode = questionBankMapper.selectOptionCode(questionId, TRUE);
                if (optionCode.size() == 0) {
                    throw new QuestionAnswerIsNullException();
                } else {
                    List<String> correctAnswer = new ArrayList<>();
                    for (Map<String, Object> stringObjectMap : optionCode) {
                        correctAnswer.add(stringObjectMap.get("optionCode").toString());
                    }

                    StringBuilder userQuestionAnswers = new StringBuilder();
                    for (String s : userQuestionAnswer) {
                        userQuestionAnswers.append(s).append(" ");
                    }

                    if (userQuestionAnswer.equals(correctAnswer)) {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                TRUE,
                                userQuestionAnswers.toString()
                        );
                        map.put("answerIsCorrect", TRUE);
                    } else {
                        questionBankMapper.insertUserAnswerQuestion(
                                user.getUsername(),
                                questionId,
                                FALSE,
                                userQuestionAnswers.toString()
                        );
                        map.put("answerIsCorrect", FALSE);
                    }
                    map.put("correctAnswer", correctAnswer);
                    return map;
                }
            }
        }
    }

    @Override
    public Map<String, Object> getTestOfCredentialIdOf(Integer credentialId) throws TestException {
        Map<String, Object> res = new HashMap<>();
        List<Map<String, Object>> questionsByType = new ArrayList<>();

        //随机取一张测试卷
        TestInfo test = questionBankMapper.selectRandomTestIdOfCredential(credentialId);
        if (test == null)
            throw new EmptyTestOfTheCredentialException();
        res.put("testInfo", test);

        //按照类型将题号取出
        for (String questionType : questionTypes) {
            Map<String, Object> tmp = new HashMap<>();
            List<Integer> questionIds = questionBankMapper.selectQuestionIdOfTestByType(test.getId(), questionType);
            tmp.put("questionType", questionType);
            tmp.put("questionIds", questionIds);
            questionsByType.add(tmp);
        }
        res.put("questionsByType", questionsByType);

        return res;
    }

    @Override
    public List<Map<String, Object>> getTestsOfProfessionOf(Integer professionId) throws TestException {
        List<Map<String, Object>> res = questionBankMapper.selectTestsByProfessionId(professionId);
        if (res.size() == 0)
            throw new EmptyTestOfTheProfessionException();
        return res;
    }

    public List<Map<String, Object>> getQuestionInformationGeneral(Integer id) {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        String x = user.getUsername();
        List<Map<String, Object>> y = questionBankMapper.selectQuestionInformation(x, id);
        int i = 0;
        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("单选")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "单选");
            a.put("answerNumber", 0);
            y.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("多选")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "多选");
            a.put("answerNumber", 0);
            y.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("填空")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "填空");
            a.put("answerNumber", 0);
            y.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("判断")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "判断");
            a.put("answerNumber", 0);
            y.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("论述")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "论述");
            a.put("answerNumber", 0);
            y.add(a);
        }
        i = 0;
        List<Map<String, Object>> z = questionBankMapper.selectQuestionNumber(id);

        for (Map<String, Object> tmp : z) {
            if (tmp.get("type").equals("单选")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "单选");
            a.put("allNumber", 0);
            z.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : z) {
            if (tmp.get("type").equals("多选")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "多选");
            a.put("allNumber", 0);
            z.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : z) {
            if (tmp.get("type").equals("填空")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "填空");
            a.put("allNumber", 0);
            z.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : z) {
            if (tmp.get("type").equals("判断")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "判断");
            a.put("allNumber", 0);
            z.add(a);
        }
        i = 0;
        for (Map<String, Object> tmp : z) {
            if (tmp.get("type").equals("论述")) {
                i = 1;
                break;
            }
        }
        if (i == 0) {
            Map<String, Object> a = new HashMap<>();
            a.put("type", "论述");
            a.put("allNumber", 0);
            z.add(a);
        }
        i = 0;

        for (Map<String, Object> tmp : y) {
            if (tmp.get("type").equals("单选")) {
                for (Map<String, Object> temp : z) {
                    if (temp.get("type").equals("单选")) {
                        tmp.put("allNumber", temp.get("allNumber"));
                    }
                }

            }
            if (tmp.get("type").equals("多选")) {
                for (Map<String, Object> temp : z) {
                    if (temp.get("type").equals("多选")) {
                        tmp.put("allNumber", temp.get("allNumber"));
                    }
                }

            }
            if (tmp.get("type").equals("判断")) {
                for (Map<String, Object> temp : z) {
                    if (temp.get("type").equals("判断")) {
                        tmp.put("allNumber", temp.get("allNumber"));
                    }
                }

            }
            if (tmp.get("type").equals("论述")) {
                for (Map<String, Object> temp : z) {
                    if (temp.get("type").equals("论述")) {
                        tmp.put("allNumber", temp.get("allNumber"));
                    }
                }

            }
            if (tmp.get("type").equals("填空")) {
                for (Map<String, Object> temp : z) {
                    if (temp.get("type").equals("填空")) {
                        tmp.put("allNumber", temp.get("allNumber"));
                    }
                }

            }
        }
        return y;
    }

    @Override
    public Map<String, Object> getQuestionAnalysis(Integer id, String type) throws QuestionAnalysisException {
        List<Map<String, Object>> x;
        Map<String, Object> d = new HashMap<>();
        if (type.equals("单选") || type.equals("多选")) {
            String s = questionBankMapper.selectType(id);
            if (type.equals(s) == FALSE)
                throw new TypeErrException();
            x = questionBankMapper.selectOptionQuestionAnalysis(id);
            String a = (String) (x.get(0)).get("analysis");
            StringBuilder u = new StringBuilder();
            boolean isFirst = true;
            for (Map<String, Object> tmp : x) {
                String z = (String) tmp.get("code");
                tmp.put("optionText", z + ":" + tmp.get("optionText"));
                tmp.remove("code");
                tmp.put("answer", tmp.get("optionText"));
                if (isFirst)
                    isFirst = false;
                else
                    u.append(" ");
                u.append((String) tmp.get("optionText"));
                tmp.remove("optionText");
                tmp.remove("analysis");
            }
            d.put("answer", u.toString());
            d.put("analysis", a);


        } else if (type.equals("判断")) {
            String s = questionBankMapper.selectType(id);
            if (type.equals(s) == FALSE)
                throw new TypeErrException();
            x = questionBankMapper.selectJudgeQuestionAnalysis(id);
            String v = (x.get(0)).get("isCorrect").toString();
            d.put("answer", v);
            String a = (String) (x.get(0)).get("analysis");
            d.put("analysis", a);
        } else {
            String s = questionBankMapper.selectType(id);
            if (type.equals(s) == FALSE)
                throw new TypeErrException();
            x = questionBankMapper.selectTextQuestionAnalysis(id);
            if ((x.get(0)).get("text") != null) {
                String v = (x.get(0)).get("text").toString();
                d.put("answer", v);
            } else d.put("answer", null);
            if ((x.get(0)).get("analysis") != null) {
                String a = (String) (x.get(0)).get("analysis");
                d.put("analysis", a);
            } else d.put("analysis", null);
        }
        return d;
    }

    @Override
    public List<Map<String, Object>> getQuestionErr() throws QuestionErrException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        String x = user.getUsername();
        List<Map<String, Object>> y = questionBankMapper.selectQuestionErr(x);
        if (y.size() == 0)
            throw new NoErrQuestionException();
        else return y;
    }

    @Override
    public MyPageInfo getQuestionInformation(Integer bankId, String type, Integer pageNo, Integer pageSize
    ) throws QuestionInformationException {
        List<Map<String, Object>> x;
        PageHelper.startPage(pageNo, pageSize);
        if (type.equals("单选") || type.equals("多选")) {
            List<Map<String, Object>> a = questionBankMapper.selectQuestionText(bankId, type);
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(a);
            if (a.size() == 0)
                throw new NoQuestionInformationException();
            x = questionBankMapper.selectQuestionOpinionText(bankId);
            for (Map<String, Object> tmp : x) {
                String z = (String) tmp.get("code");
                if (z != null)
                    tmp.put("optionText", z + ":" + tmp.get("optionText"));
                tmp.remove("code");
                if (tmp.get("optionText") == null)
                    tmp.remove("optionText");
                else {
                    tmp.put("option", tmp.get("optionText"));
                }
                tmp.remove("optionText");
            } //把x中的code 和option text合在一起，名称为option
            for (Map<String, Object> temp : pageInfo.getList()) {
                Integer id = (Integer) temp.get("questionId");//获得题目id
                List<String> questionOption = new ArrayList<>();
                for (Map<String, Object> tmp : x) {
                    if (id == (int) tmp.get("questionId")) {
                        if (tmp.get("option") != null)
                            questionOption.add((String) tmp.get("option"));
                    }
                }
                int e = questionOption.size();
                if (e != 0) {
                    temp.put("option", questionOption);
                }
                temp.remove("questionId");
            }
            return new MyPageInfo(pageInfo);
        } else if (type.equals("填空") || type.equals("论述")) {
            List<Map<String, Object>> a = questionBankMapper.selectCommunicateText(bankId, type);
            if (a.size() == 0)
                throw new NoQuestionInformationException();
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(a);
            return new MyPageInfo(pageInfo);
        } else {
            List<Map<String, Object>> a = questionBankMapper.selectJudgeText(bankId);
            if (a.size() == 0)
                throw new NoQuestionInformationException();
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(a);
            return new MyPageInfo(pageInfo);
        }

    }

    @Override
    public void signTheQuestion(Integer questionId) {
        if (questionBankMapper.selectQuestionById(questionId) == null)
            throw new NoQuestionInformationException();
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        if (questionBankMapper.selectUserSignQuestion(user.getUsername(), questionId) != null)
            throw new MultiSignOfSameQuestionException();
        Integer res = questionBankMapper.insertUserSignQuestion(user.getUsername(), questionId);
        if (res == 0)
            throw new BusyException();
    }

    @Override
    public void removeSignOfTheQuestion(Integer questionId) {
        if (questionBankMapper.selectQuestionById(questionId) == null)
            throw new NoQuestionInformationException();
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        if (questionBankMapper.selectUserSignQuestion(user.getUsername(), questionId) == null)
            throw new InvalidSignOfTheQuestionException();
        Integer res = questionBankMapper.deleteUserSignQuestion(user.getUsername(), questionId);
        if (res == 0)
            throw new BusyException();
    }

    @Override
    public List<Integer> getErr() throws QuestionErrIdException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        List<Integer> x = questionBankMapper.selectErr(user.getUsername());
        if (x.size() == 0)
            throw new NoQuestionErrIdException();
        return x;
    }

    @Override
    public Map<String, Object> getErrQuestionInformation(Integer id) throws QuestionInformationException {
        String type = questionBankMapper.selectType(id);
        Map<String, Object> a = new HashMap<>();
        if (type.equals("判断")) {
            a.put("text", questionBankMapper.selectErrQuestionText(id));
        } else {
            int i = 1;
            StringBuilder option = new StringBuilder();
            a.put("text", questionBankMapper.selectErrQuestionText(id));
            List<Map<String, Object>> z = questionBankMapper.selectErrQuestionOpinionText(id);
            for (Map<String, Object> tmp : z) {
                if (i == 1) {
                    option.append(tmp.get("code").toString()).append(":").append(tmp.get("optionText"));
                    i = 0;
                } else option.append(" ").append(tmp.get("code").toString()).append(":").append(tmp.get("optionText"));
            }
            a.put("option", option.toString());
        }
        if (a.get("text") == null) {
            throw new NoQuestionInformationException();
        }
        return a;
    }

    @Override
    public List<String> getUserQuestionAnswer(Integer id) throws QuestionBankException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        List<Map<String, Object>> userAnswerQuestion =
                questionBankMapper.selectUserAnswerQuestion(user.getUsername(), id);
        if (userAnswerQuestion.size() == 0) {
            return null;
        } else {
            List<String> userAnswer;
            userAnswer = Arrays.asList(userAnswerQuestion.get(0).get("usersAnswer").toString().split(" "));
            return userAnswer;
        }
    }

    @Override
    public Map<String, Object> getQuestionCard(Integer bankId, String type) throws QuestionCardException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        Integer[] sign = questionBankMapper.selectCardSign(user.getUsername(), bankId, type);
        Integer[] correct = questionBankMapper.selectCardCorrect(user.getUsername(), bankId, type);
        Integer[] error = questionBankMapper.selectCardErr(user.getUsername(), bankId, type);
        Integer[] question = questionBankMapper.selectCardQuestion(bankId, type);
        Boolean[] e = new Boolean[question.length];
        Boolean[] f = new Boolean[question.length];
        if (question.length == 0) {
            throw new NoQuestionCardException();
        }
        for (Boolean b : e) {
            b = null;
        }
        for (Boolean b : f) {
            b = null;
        }
        int i = 0;
        for (int x : question) {
            for (int y : correct) {
                if (y == x) {
                    e[i] = true;
                    break;
                }

            }
            for (int y : error) {
                if (y == x) {
                    e[i] = false;
                    break;
                }
            }
            i++;
        }
        i = 0;
        for (int x : question) {
            for (int y : sign) {
                if (y == x) {
                    f[i] = true;
                    break;
                }

            }
            i++;
        }


        Map<String, Object> z = new HashMap<>();
        z.put("sign", f);
        z.put("isCorrect", e);
        z.put("questionId", question);
        return z;

    }

    @Override
    public Map<String, Object> getMessage(Integer id) throws NoQuestionMessageException {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        Map<String, Object> x = questionBankMapper.selectQuestionMessage(user.getUsername(), id);
        if (x == null)
            throw new NoQuestionMessageException();
        x.put("date", x.get("date").toString());
        return x;
    }


}


